﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetFramework.Cache;
using NetFramework.Diagnostics;
using NetFramework.Logging;

namespace NetFramework.Configuration
{
    public abstract class ConfigSourceBase : IConfigSource
    {
        private static readonly object lockSycnOject = new object();
        private static Dictionary<string, IConfigParameter> fileConfigParameterCacheList = new Dictionary<string, IConfigParameter>();

        protected ILogger log;

        public ConfigSourceBase()
        {
            log = LoggerManager.GetLog(this.GetType());
        }

        /// <summary>
        /// 获取配置文件路径参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        protected virtual IConfigParameter GetFileConfigParameter(Type type)
        {
            string key = GetFileConfigParameterCacheKey(type);

            IConfigParameter param;
            if (!fileConfigParameterCacheList.TryGetValue(key, out param))
            {
                ConfigFileAttribute attr = Attribute.GetCustomAttribute(type, typeof(ConfigFileAttribute)) as ConfigFileAttribute;
                
                Ensure.ArgumentNotNull(attr, "ConfigFile");
                if (string.IsNullOrEmpty(attr.SectionName))
                {
                    param = new FileConfigParameter(attr.FileName, attr.FileName, attr.Cacheable);
                }
                else
                {
                    param = new FileConfigParameter(attr.SectionName, attr.FileName, attr.Cacheable);
                }

                fileConfigParameterCacheList[key] = param;
            }

            return param;
        }

        protected abstract T GetConfigFromSource<T>(IConfigParameter parameter) where T : class, new();

        public virtual T GetConfig<T>() where T : class, new()
        {
            Type type = typeof(T);
            string key = GetFileConfigCacheKey(type);

            T retrieveObject = CacheManager.Get<T>(key);
            if (retrieveObject == null)
            {
                // LOCK
                lock (lockSycnOject)
                {
                    retrieveObject = CacheManager.Get<T>(key);
                    if (retrieveObject == null)
                    {
                        IConfigParameter configParameter = GetFileConfigParameter(type);
                        retrieveObject = GetConfigFromSource<T>(configParameter);

                        if (retrieveObject != null && configParameter.Cacheable)
                        {
                            CacheManager.Insert<T>(key, retrieveObject, new CacheDependency(configParameter.Files));
                        }
                    }
                }
            }

            return retrieveObject;
        }

        public virtual T GetConfig<T>(string filePath) where T : class, new()
        {
            Type type = typeof(T);
            string key = GetFileConfigCacheKey(type);

            T retrieveObject = CacheManager.Get<T>(key);
            if (retrieveObject == null)
            {
                // LOCK
                lock (lockSycnOject)
                {
                    retrieveObject = CacheManager.Get<T>(key);
                    if (retrieveObject == null)
                    {
                        IConfigParameter configParameter = new FileConfigParameter(filePath, filePath);
                        retrieveObject = GetConfigFromSource<T>(configParameter);

                        if (retrieveObject != null && configParameter.Cacheable)
                        {
                            CacheManager.Insert<T>(key, retrieveObject, new CacheDependency(configParameter.Files));
                        }
                    }
                }
            }

            return retrieveObject;
        }

        public virtual T GetConfig<T>(IConfigParameter configParameter) where T : class, new()
        {
            Type type = typeof(T);
            string key = GetFileConfigCacheKey(type);

            T retrieveObject = CacheManager.Get<T>(key);
            if (retrieveObject == null)
            {
                // LOCK
                lock (lockSycnOject)
                {
                    retrieveObject = CacheManager.Get<T>(key);
                    if (retrieveObject == null)
                    {
                        retrieveObject = GetConfigFromSource<T>(configParameter);

                        if (retrieveObject != null && configParameter.Cacheable)
                        {
                            CacheManager.Insert<T>(key, retrieveObject, new CacheDependency(configParameter.Files));
                        }
                    }
                }
            }

            return retrieveObject;
        }

        /// <summary>
        /// 生成配置文件的路径设置文件
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private string GetFileConfigCacheKey(Type type)
        {
            return string.Format("ASP.ENT_FileConfig_Cache_Key_{0}", type.FullName);
        }

        /// <summary>
        /// 生成配置文件的路径设置文件
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private string GetFileConfigParameterCacheKey(Type type)
        {
            return string.Format("ASP.ENT_FileConfig_Parameter_Cache_Key_{0}", type.FullName);
        }
    }
}
